/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package npcSystem.mainCharSystem;

import tools.*;
import java.awt.*;
import java.awt.event.KeyEvent;

import npcSystem.NPC;
import npcSystem.enemies.Enemy;


import levelSystem.*;

public class MainChar extends NPC {
    
	/* Attack */
	private Weapon curWeapon;
	
    /* Movement keys */
    private boolean upKeyPressed;
    private boolean downKeyPressed;
    private boolean leftKeyPressed;
    private boolean rightKeyPressed;
    
    /* Interaction keys */
    private boolean aKeyPressed;
    private boolean sKeyPressed;
    private boolean dKeyPressed;
    private boolean wKeyPressed;
    
    private int lastKeyPressed;
    
    private double xView;
    private double yView;
    
    /* Ataque */
    private Rect attackRect;
    private int attackPower;
    
    private boolean eating; 
    
    /* Animacao */
    private int prevDir;
    
    /* Outros */

    /* Construtores */
    public MainChar(MapLevel l) {
        this(0, 0, 0, 0, new Rect(), l);
    }
    public MainChar(Rect t, MapLevel l)
    {
    	this(t.x, t.y, 0, 0, new Rect(), l);
    }
    public MainChar(double x, double y, int lw, int lh, Rect c, MapLevel l) {
        super();
    	
        curLevel = l;
        
        eating = false;
        
    	sprite = ImageHandler.loadImage("/img/mainChar/mainChar.png");
    	sprite = ImageHandler.addColorKey(sprite);
        
    	curWeapon = null;
    	
        //me = new Rect(x, y, 21, 30);
        me = new Rect(x, y, Constants.MAIN_CHAR_WIDTH, Constants.MAIN_CHAR_HEIGHT);
    	attackRect = new Rect(x, y, Constants.MAIN_CHAR_WIDTH, Constants.MAIN_CHAR_HEIGHT);
        attackPower = 0;
        
        cam = c;
                
        maxHealth = 3;
        health = 3;
        maxImuneTime = 15;
        maxDeadFrames = 0;
        
        maxKnockedBackTime = 10;
        
        vel = Constants.MAIN_CHAR_DEFAULT_VEL;
        levelWidth = lw;
        levelHeight = lh;
        
        upKeyPressed = false;
        downKeyPressed = false;
        leftKeyPressed = false;
        rightKeyPressed = false;
        
        aKeyPressed = false;
        sKeyPressed = false;
        dKeyPressed = false;
        wKeyPressed = false;
        
        xView = x - me.w;
        yView = y + me.h/2;
        
        curDir = 1;
        prevDir = 3;
        maxFrameSkip = Constants.DEFAULT_MAX_FRAME_SKIP;
        
        if(sprite != null)
        {
        	int maxRows = sprite.getHeight()/Constants.MAIN_CHAR_SPRITE_HEIGHT;
        	int maxCols = sprite.getWidth()/Constants.MAIN_CHAR_SPRITE_WIDTH;
	        
        	maxCurFrame = maxCols;
	        
	        clips = new Rect[maxRows][maxCols];
	        
	        initClips();
	        setClips();
        }
        
        try
    	{
    		MainCharSounds.init();
    	}catch(ExceptionInInitializerError e)
    	{
    		e.printStackTrace();
    	}
    }
  
    @Override
    public void draw(Graphics g)
    {
    	if(!curLevel.isPaused())setCurFrame();
    	if(eating) drawEatingSprites(g);
    	else if(attacking) drawAttackSprites(g);
        else if(moving) drawMovingSprites(g);
        else drawStopSprites(g);
        
//        g.setColor(Color.blue); // DEBUG
//        g.fillRect((int)(me.x-cam.x), (int)(me.y - cam.y),(int) me.w, (int)me.h);
//        g.setColor(Color.red);
//        g.fillRect((int)(attackRect.x-cam.x), (int)(attackRect.y-cam.y),(int) attackRect.w, (int)attackRect.h);
    }
	@Override
    protected void setCurFrame()
    {
    	frameSkipCount++;
        if(frameSkipCount >= maxFrameSkip)
        {
        	curFrame++;
            if(curFrame >= maxCurFrame && !dead)
            {
            	if(attacking)
            	{
            		maxFrameSkip = Constants.DEFAULT_MAX_FRAME_SKIP;
            		try {
						attackRect = (Rect) me.clone();
					} catch (CloneNotSupportedException e) {}
            		attacking = false;
            	}
            	curFrame = 0;
            }if(dead) curFrame = 0;
            frameSkipCount = 0;
        }
    }
    @Override
    protected void drawMovingSprites(Graphics g)
    {
    	g.drawImage(sprite.getSubimage((int)clips[curDir-1][curFrame].x, 
				   (int)clips[curDir-1][curFrame].y, 
				   (int)clips[curDir-1][curFrame].w, 
				   (int)clips[curDir-1][curFrame].h), 
				   (int)(me.x - cam.x - Constants.DELTA_X), 
				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    }
    @Override
    protected void drawStopSprites(Graphics g)
    {
    	g.drawImage(sprite.getSubimage((int)clips[curDir+3][curFrame].x, 
				   (int)clips[curDir+3][curFrame].y, 
				   (int)clips[curDir+3][curFrame].w, 
				   (int)clips[curDir+3][curFrame].h), 
				   (int)(me.x - cam.x - Constants.DELTA_X), 
				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    }   
    @Override    
    protected void drawAttackSprites(Graphics g)
    {
    	if(curWeapon != null)
    	{
	    	if(lastKeyPressed == KeyEvent.VK_S) 
	    	{
	    		drawLightsprite(g);
	    		curWeapon.draw(g, curFrame, curDir, 1, me.x, me.y, cam);
	    	}
	    	else 
	    	{
	    		drawHeavysprite(g);
	    		curWeapon.draw(g, curFrame, curDir, 2, me.x, me.y, cam);
	    	}
	    	
    	}
    }
	private void drawLightsprite(Graphics g)
    {
    	if(curDir == 1)
    	{
    		g.drawImage(sprite.getSubimage((int)clips[curDir+7][curFrame].x, 
 				   (int)clips[curDir+7][curFrame].y, 
 				   (int)clips[curDir+7][curFrame].w, 
 				   (int)clips[curDir+7][curFrame].h), 
 				   (int)(me.x - cam.x - Constants.DELTA_X), 
 				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    	}else if(curDir == 3)
    	{
    		g.drawImage(sprite.getSubimage((int)clips[curDir+7][curFrame].x, 
 				   (int)clips[curDir+7][curFrame].y, 
 				   (int)clips[curDir+7][curFrame].w, 
 				   (int)clips[curDir+7][curFrame].h), 
 				   (int)(me.x - cam.x - Constants.DELTA_X), 
 				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    	}else if(curDir == 4)
    	{
    		g.drawImage(sprite.getSubimage((int)clips[curDir+7][curFrame].x, 
 				   (int)clips[curDir+7][curFrame].y, 
 				   (int)clips[curDir+7][curFrame].w, 
 				   (int)clips[curDir+7][curFrame].h), 
 				   (int)(me.x - cam.x - Constants.DELTA_X), 
 				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    	}else
    	{
    		g.drawImage(sprite.getSubimage((int)clips[curDir+7][curFrame].x, 
 				   (int)clips[curDir+7][curFrame].y, 
 				   (int)clips[curDir+7][curFrame].w, 
 				   (int)clips[curDir+7][curFrame].h), 
 				   (int)(me.x - cam.x - Constants.DELTA_X), 
 				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    	}
    }
    private void drawHeavysprite(Graphics g)
    {
    	if(curDir == 1)
    	{
    		g.drawImage(sprite.getSubimage((int)clips[curDir+11][curFrame].x, 
 				   (int)clips[curDir+11][curFrame].y, 
 				   (int)clips[curDir+11][curFrame].w, 
 				   (int)clips[curDir+11][curFrame].h), 
 				   (int)(me.x - cam.x - Constants.DELTA_X), 
 				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    	}else if(curDir == 3)
    	{
    		g.drawImage(sprite.getSubimage((int)clips[curDir+11][curFrame].x, 
 				   (int)clips[curDir+11][curFrame].y, 
 				   (int)clips[curDir+11][curFrame].w, 
 				   (int)clips[curDir+11][curFrame].h), 
 				   (int)(me.x - cam.x - Constants.DELTA_X), 
 				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    	}else if(curDir == 4)
    	{
    		g.drawImage(sprite.getSubimage((int)clips[curDir+11][curFrame].x, 
 				   (int)clips[curDir+11][curFrame].y, 
 				   (int)clips[curDir+11][curFrame].w, 
 				   (int)clips[curDir+11][curFrame].h), 
 				   (int)(me.x - cam.x - Constants.DELTA_X), 
 				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    	}else
    	{
    		g.drawImage(sprite.getSubimage((int)clips[curDir+11][curFrame].x, 
 				   (int)clips[curDir+11][curFrame].y, 
 				   (int)clips[curDir+11][curFrame].w, 
 				   (int)clips[curDir+11][curFrame].h), 
 				   (int)(me.x - cam.x - Constants.DELTA_X), 
 				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
    	}
    }
    private void drawEatingSprites(Graphics g) {
    	g.drawImage(sprite.getSubimage((int)clips[curDir+15][curFrame].x, 
				   (int)clips[curDir+15][curFrame].y, 
				   (int)clips[curDir+15][curFrame].w, 
				   (int)clips[curDir+15][curFrame].h), 
				   (int)(me.x - cam.x - Constants.DELTA_X), 
				   (int)(me.y - cam.y - Constants.DELTA_Y), null);
	}
    
    @Override
    public void move()
    {
    	if(!attacking && !curLevel.mapHasChanged() && !eating)
    	{
	        me.x += xVel; 
	        if(me.x < 0) me.x = 0;
	        if(me.x + me.w > curLevel.getLevelWidth()) me.x = curLevel.getLevelWidth() - me.w;
	        if(hitWall(curLevel.getShowingWalls())) me.x -= xVel;
	        
	        me.y += yVel;
	        if(me.y < 0) me.y = 0;
	        if(me.y + me.h > curLevel.getLevelHeight()) me.y = curLevel.getLevelHeight() - me.h;
	        if(hitWall(curLevel.getShowingWalls())) me.y -= yVel;
	        
	        try {
				attackRect = (Rect) me.clone();
			} catch (CloneNotSupportedException e) {}
	        
    	}else
    	{
    		curLevel.mapReady();
    	}
    }
    private void attack() {
    	for(Enemy enm : curLevel.getEnemies())
    	{
    		if(!enm.isImune())
    		{
    			if(Physics.checkBlockCollision(attackRect, enm.getMe()))
    			{
    				int xv = 0;
    				int yv = 0;
    				
    				if(curDir == 1) xv = -1;
    				if(curDir == 2) xv = 1;
    				if(curDir == 3) yv = -1;
    				if(curDir == 4) yv = 1;
    				
    				enm.beingHit(attackPower, xv, yv);
    			}
    		}
    	}
    }
    private void setAttack()
    {
    	/* Modo cabaco */
    	if((attackRect.x == me.x && attackRect.y == me.y) || curDir != prevDir)
    	{
    		prevDir = curDir;
    		// mudar depois
    		switch(curDir)
    		{
    			case 1:
    				attackRect.x = me.x - attackRect.w;
    				attackRect.y = me.y;
    				break;
    			case 2:
    				attackRect.x = me.x+me.w;
    				attackRect.y = me.y;
    				break;
    			case 3:
    				attackRect.x = me.x;
    				attackRect.y = me.y-attackRect.h;
    				break;
    			case 4:
    				attackRect.x = me.x;
    				attackRect.y = me.y+me.h;
    				break;
    		}
    	}
    }
    public void setWeapon(Weapon w)
    {
    	curWeapon = w;
    }
    
    private void setView()
    {
    	switch(curDir)
    	{
    		case 1:
    			xView = me.x - me.w;
    			yView = me.y + me.h/2;
    			break;
    		case 2:
    			xView = me.x + me.w*2;
    			yView = me.y + me.h/2;
    			break;
    		case 3:
    			xView = me.x + me.w/2;
    			yView = me.y;
    			break;
    		case 4:
    			xView = me.x + me.w/2;
    			yView = me.y + me.h*1.5;
    			break;
    	}
    }
    public double getXView()
    {
    	return xView;
    }
    public double getYView()
    {
    	return yView;
    }
    
    public void processKey(int keyCode, int type)
    {
    	if(!dead)
    	{
	        if(type == 1) // key pressed
	        {
	        	lastKeyPressed = keyCode;
	            switch(keyCode)
	            {
	                case KeyEvent.VK_UP:
	                    if(!upKeyPressed)
	                    {
	                        upKeyPressed = true;
	                        yVel -= vel;
	                    }
	                    
	                    if(downKeyPressed && !anyHorizontalKeyPressed()) moving = false;
	                    else moving = true;
	                    
	                    if(bothHorizontalKeyPressed()) curDir = 3;
	                    else if(leftKeyPressed) curDir = 1;
	                    else if(rightKeyPressed) curDir = 2;
	                    else curDir = 3;
	                    break;
	                case KeyEvent.VK_DOWN:
	                    if(!downKeyPressed)
	                    {
	                        downKeyPressed = true;
	                        yVel += vel;
	                    }
	                    
	                    if(upKeyPressed && !anyHorizontalKeyPressed()) moving = false;
	                    else moving = true;
	                    
	                    if(bothHorizontalKeyPressed()) curDir = 4;
	                    else if(leftKeyPressed) curDir = 1;
	                    else if(rightKeyPressed) curDir = 2;
	                    else curDir = 4;
	                    break;
	                case KeyEvent.VK_LEFT:
	                    if(!leftKeyPressed)
	                    {
	                        leftKeyPressed = true;
	                        xVel -= vel;
	                    }
	                    if(rightKeyPressed && !anyVerticalKeyPressed()) moving = false;
	                    else moving = true;
	                    
	                    if(rightKeyPressed && downKeyPressed) curDir = 4;
	                    else if(rightKeyPressed && upKeyPressed) curDir = 3;
	                    else curDir = 1;
	                    break;
	                case KeyEvent.VK_RIGHT:
	                    if(!rightKeyPressed)
	                    {
	                        rightKeyPressed = true;
	                        xVel += vel;
	                    }
	                    if(leftKeyPressed && !anyVerticalKeyPressed()) moving = false;
	                    else moving = true;
	                    
	                    if(leftKeyPressed && downKeyPressed) curDir = 4;
	                    else if(leftKeyPressed && upKeyPressed) curDir = 3;
	                    else curDir = 2;
	                    break;
	                case KeyEvent.VK_A:
	                    if(!aKeyPressed)
	                    {
	                        interact();
	                        aKeyPressed = true;
	                    }
	                    break;
	                case KeyEvent.VK_S: // So aceita um ataque por vez
	                	if(!sKeyPressed && !dKeyPressed)
	                    {
	                        sKeyPressed = true;
	                		if(curWeapon == null)
	                		{
	                			interact();
	                		}else
	                		{
		                        lightAttack();
		                        MainCharSounds.attack.play();
		                        attacking = true;
		                        maxFrameSkip = 2;
		                        curFrame = 0;
	                		}
	                    }
	                    break;
	                case KeyEvent.VK_D:
	                    if(!dKeyPressed && !sKeyPressed)
		                {
	                    	dKeyPressed = true;
		            		if(curWeapon == null)
		            		{
		            			interact();
		            		}else
		            		{
		                        heavyAttack();
		                        MainCharSounds.attack.play();
		                        attacking = true;
		                        maxFrameSkip = 2;
		                        curFrame = 0;
		            		}
	                    }
	                    break;
	                case KeyEvent.VK_W:
	                    if(!wKeyPressed)
	                    {
	                    	eating = true;
	                        wKeyPressed = true;
	                    }
	                    break;
	            }
	        }
	        if(type == 2) // key released
	        {
	            switch(keyCode)
	            {
	                case KeyEvent.VK_UP: 
	                    upKeyPressed = false;
	                    if(!otherDirectionalKeyPressed()) moving = false;
	                    else
	                    {
	                    	moving = true;
	                    	if(bothHorizontalKeyPressed())
	                    	{
	                    		moving = false;
	                    		curDir = 3;
	                    	}
	                    	else if(leftKeyPressed) curDir = 1;
	                    	else if(rightKeyPressed) curDir = 2;
	                    	else curDir = 3;
	                    }
	                    yVel += vel;
	                    break;
	                case KeyEvent.VK_DOWN:
	                    downKeyPressed = false;
	                    if(!otherDirectionalKeyPressed()) moving = false;
	                    else
	                    {
	                    	moving = true;
	                    	if(bothHorizontalKeyPressed())
	                    	{
	                    		moving = false;
	                    		curDir = 4;
	                    	}
	                    	else if(leftKeyPressed) curDir = 1;
	                    	else if(rightKeyPressed) curDir = 2;
	                    	else curDir = 4;
	                    }
	                    yVel -= vel;
	                    break;
	                case KeyEvent.VK_LEFT: 
	                    leftKeyPressed = false;
	                    if(!otherDirectionalKeyPressed()) moving = false;
	                    else
	                    {
	                    	moving = true;
	                    	if(rightKeyPressed) curDir = 2;
	                    	else if(bothVerticalKeyPressed()) moving = false;
	                    	else if(upKeyPressed) curDir = 3;
	                    	else if(downKeyPressed) curDir = 4;
	                    }
	                    xVel += vel;
	                    break;
	                case KeyEvent.VK_RIGHT:
	                    rightKeyPressed = false;
	                    if(!otherDirectionalKeyPressed()) moving = false;
	                    else
	                    {
	                    	moving = true;
	                    	if(leftKeyPressed) curDir = 1;
	                    	else if(bothVerticalKeyPressed()) moving = false;
	                    	else if(upKeyPressed) curDir = 3;
	                    	else if(downKeyPressed) curDir = 4;
	                    }
	                    xVel -= vel;
	                    break;
	                case KeyEvent.VK_A:
	                    aKeyPressed = false;
	                    break;
	                case KeyEvent.VK_S:
	                    sKeyPressed = false;
	                    break;
	                case KeyEvent.VK_D:
	                    dKeyPressed = false;
	                    break;
	                case KeyEvent.VK_W:
	                	eating = false;
	                    wKeyPressed = false;
	                    break;
	            }
	        }
    	}
    }
    private boolean otherDirectionalKeyPressed()
    {
    	return anyHorizontalKeyPressed() | anyVerticalKeyPressed();
    }
    private boolean anyHorizontalKeyPressed()
    {
    	return leftKeyPressed | rightKeyPressed;
    }
    private boolean anyVerticalKeyPressed()
    {
    	return upKeyPressed | downKeyPressed;
    }
    private boolean bothHorizontalKeyPressed()
    {
    	return leftKeyPressed & rightKeyPressed;
    }
    private boolean bothVerticalKeyPressed()
    {
    	return upKeyPressed & downKeyPressed;
    }
    
    @Override
    public int logic()
    {
    	if(sprite == null)
    	{
    		return -1;
    	}
    	if(eating)
    	{
    		MainCharSounds.eat.play();
    		eatPacoca();
    	}
    	if(attacking)
    	{
    		setAttack();
    		attack();
    	}
        if(health <= 0) die();
        if(!dead)
        {
        	// nao implementado
        	if(imune) calcImuneTime();
        	if(!anyHorizontalKeyPressed() && xVel != 0 && !knockedBack) xVel = 0; // correcao de velocidade
        	if(!anyVerticalKeyPressed() && yVel != 0 && !knockedBack) yVel = 0;   // caso trave
        }else
        {
        	deadFrames++;
        	if(deadFrames >= maxDeadFrames) return 1;
        }
        
        setView();
    	
        return 0;
    }
    
    public void stop()
    {
    	xVel = 0;
    	yVel = 0;
    	
    	upKeyPressed = false;
    	downKeyPressed = false;
    	leftKeyPressed = false;
    	rightKeyPressed = false;
    }
    public void die()
    {
    	stop();
    	
    	curFrame = 0;
    	
    	dead = true;
    }
    public void beingHit(double xv, double yv)
    {
    	if(!imune)
    	{
	    	health--;
	    	knockedBack = true;
	    	knockedBackTime = 0;
	    	
	    	MainCharSounds.beingHit.play();
	    	
	    	int ix = (int) (xv/Math.abs(xv));
	    	int iy = (int) (yv/Math.abs(yv));
	    	
	    	for(int i = 0; i < Constants.TILE_WIDTH; i++) // mover um tile pra tras, se possivel
	    	{
	    		me.x += ix;
	    		if(me.x < 0) me.x = 0;
	    		if(me.x + me.w > curLevel.getLevelWidth()) me.x = curLevel.getLevelWidth() - me.w;
	    		if(hitWall(curLevel.getShowingWalls())) me.x -= ix;
	    		
	    		me.y += iy;
	    		if(me.y < 0) me.y = 0;
	    		if(me.y + me.h > curLevel.getLevelHeight()) me.y = curLevel.getLevelHeight() - me.h;
	    		if(hitWall(curLevel.getShowingWalls())) me.y -= iy;
	    	}
	    	
	    	imune = true;
    	}
    }
    
	private void interact() // Interagir com NPC senario
    {
        curLevel.playerInteraction(curDir);
    }
    private void lightAttack() // Ataque fraco
    {
       	attackPower = 1;
    }
    private void heavyAttack() // Ataque forte
    {
    	attackPower = 2;
    }
    private void eatPacoca() // Comer pacoca
    {
    	double x = me.x; 
    	double y = me.y;
    	
    	if(curDir == 1) x = me.x-Constants.TILE_WIDTH;
    	if(curDir == 2) x = me.x+me.w;
    	if(curDir == 3) y = me.y-Constants.TILE_HEIGHT;
    	if(curDir == 4) y = me.y+me.h;
    	
    	for(Enemy e : curLevel.getEnemies())
    	{
    		if(Physics.checkBlockCollision(new Rect(x, y, Constants.TILE_WIDTH, Constants.TILE_HEIGHT), e.getMe()))
    		{
    			e.beingEated();
    			health++;
    			if(health > maxHealth) health = maxHealth;
    		}
    	}
    }
    
    public void setCam(Rect cam)
    {
    	this.cam = cam;
    }
    public void resetKeys()
    {
    	aKeyPressed = false;
    	sKeyPressed = false;
    	dKeyPressed = false;
    	wKeyPressed = false;
    	
    	upKeyPressed = false;
    	downKeyPressed = false;
    	leftKeyPressed = false;
    	rightKeyPressed = false;
    }
	public void reset() {
		dead = false;
		
		xVel = 0;
		yVel = 0;
		
		health = maxHealth;
		
		moving = false;
		attacking = false;
		eating = false;
		
		curFrame = 0;
		maxFrameSkip = Constants.MAX_SKIPS;
	}
}
